﻿
using Cms.Core.Infrastructure.Extension;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace Cms.Core.Infrastructure.Helps
{
    public class GeneraterExpression<TIn, TOut>
    {
        public static Func<TIn, TOut> _func = null;

        static GeneraterExpression()
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
            MethodInfo methodInfoGet = typeof(TIn).GetMethod("get_Item", new Type[] { typeof(string) });
            MethodInfo methodInfoAsTo = typeof(ObjectExtensions).GetMethod("AsTo", new Type[] { typeof(Object) });

            IEnumerable<MemberBinding> memberBindings = typeof(TOut).GetProperties().Where(o => o.CanWrite).Select(propertyInfo =>
            {

                ConstantExpression constant = Expression.Constant(propertyInfo.Name);
                //调用方法 get_Item
                MethodCallExpression callGet_Item = Expression.Call(parameterExpression, methodInfoGet, constant);
                //找到静态泛型方法Asto()
                MethodInfo makeGenericMethod = methodInfoAsTo.MakeGenericMethod(new Type[] { propertyInfo.PropertyType });
                MethodCallExpression call = Expression.Call(null, makeGenericMethod, new Expression[] { callGet_Item });
                //初始化
                return Expression.Bind(propertyInfo, call);
            });


            MemberInitExpression memberInit = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindings.ToArray());
            Expression<Func<TIn, TOut>> expression = Expression.Lambda<Func<TIn, TOut>>
            (
                memberInit,
                new ParameterExpression[] { parameterExpression }
            );

            //执行..
            _func = expression.Compile();
        }
    }
}
